#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#include <X11/Xutil.h>
#include <unistd.h>
#include <vector>
#include <string.h>
#include <chrono>
#include <csignal>
#include <thread>
#include <memory>
#include "IniFileParser.h"
#include "RemoteDesktopClient.h"
#include "common.h"

// 信号处理的全局标志
volatile sig_atomic_t shutdown_requested = 0;
// 信号处理函数
void signal_handler(int signum)
{
    std::cout << "捕获到信号 " << signum << std::endl;
    shutdown_requested = 1;
}

RemoteDesktopClient::RemoteDesktopClient(std::string ip, unsigned short display_port, unsigned short controller_port, int width, int height) : display(nullptr), display_client_fd(-1), controller_client_fd(-1), ximage(nullptr)
{
    this->ip = ip;
    this->display_port = display_port;
    this->controller_port = controller_port;
    this->width = width;
    this->height = height;
    // 初始化X11
    display = XOpenDisplay(NULL);
    if (!display)
    {
        std::cerr << "Cannot open display" << std::endl;
    }

    // 创建窗口显示图像
    int screen = DefaultScreen(display);
    window = XCreateSimpleWindow(display, DefaultRootWindow(display), 10, 10, this->width, this->height, 1,
                                 BlackPixel(display, screen), WhitePixel(display, screen));
    XMapWindow(display, window);

    // // 显示图像
    // gc = XDefaultGC(display, DefaultScreen(display));
}

RemoteDesktopClient::~RemoteDesktopClient()
{
    // 清理资源
    if (ximage)
    {
        XDestroyImage(ximage);
    }
    if (window)
    {
        XDestroyWindow(display, window);
    }
    if (display)
    {
        XCloseDisplay(display);
    }

    net_tools.closeSocket(display_client_fd);
    net_tools.closeSocket(controller_client_fd);
}

bool RemoteDesktopClient::connectToDisplayServer()
{
    // 创建TCP客户端
    display_client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (display_client_fd < 0)
    {
        std::cerr << "Failed to create socket" << std::endl;
        return false;
    }

    // 设置服务器地址
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(display_port);
    if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0)
    {
        std::cerr << "Invalid address." << std::endl;
        net_tools.closeSocket(display_client_fd);
        return false;
    }

    // 连接到服务器
    if (connect(display_client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        std::cerr << "Failed to connect " << ip << ": " << display_port << std::endl;
        net_tools.closeSocket(display_client_fd);
        return false;
    }
    // std::cout << "Connected to display server, port " << display_port << std::endl;
    return true;
}

bool RemoteDesktopClient::connectToControllerServer()
{
    // 创建TCP客户端
    controller_client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (controller_client_fd < 0)
    {
        std::cerr << "Failed to create socket" << std::endl;
        return false;
    }

    // 设置服务器地址
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(controller_port);
    if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0)
    {
        std::cerr << "Invalid address." << std::endl;
        net_tools.closeSocket(controller_client_fd);
        return false;
    }

    // 连接到服务器
    if (connect(controller_client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        std::cerr << "Failed to connect " << ip << ": " << controller_port << std::endl;
        net_tools.closeSocket(controller_client_fd);
        return false;
    }
    return true;
}
unsigned long RemoteDesktopClient::getPixel(const XImage *img, int x, int y)
{
    if (!img || x < 0 || y < 0 || x >= img->width || y >= img->height)
        return 0; // 或者适当的错误处理

    // 计算偏移量
    int offset = (y * img->bytes_per_line) + (x * (img->bits_per_pixel / 8));
    unsigned long pixel = 0;

    // 根据图像的位深度直接访问内存
    switch (img->bits_per_pixel)
    {
    case 32:
    {
        unsigned long *line = (unsigned long *)((char *)img->data + offset);
        pixel = *line;
    }
    break;
    case 24:
    {
        unsigned char *line = (unsigned char *)((char *)img->data + offset);
        // 假设RGB顺序
        pixel = (line[0] << 16) | (line[1] << 8) | line[2];
    }
    break;
    // 可以添加更多的位深度情况
    default:
        std::cerr << "Unsupported image depth" << std::endl;
        break;
    }

    return pixel;
}
// 最近邻插值缩放图像
void RemoteDesktopClient::scaleImageNearest(const XImage *src, XImage *dst)
{
    int srcWidth = src->width;
    int srcHeight = src->height;
    int dstWidth = dst->width;
    int dstHeight = dst->height;
    float scaleX = (float)srcWidth / dstWidth;
    float scaleY = (float)srcHeight / dstHeight;

    for (int dstY = 0; dstY < dstHeight; ++dstY)
    {
        for (int dstX = 0; dstX < dstWidth; ++dstX)
        {
            // 使用最近邻插值法计算源图像中对应的点
            int srcX = std::min((int)(dstX * scaleX), srcWidth - 1);
            int srcY = std::min((int)(dstY * scaleY), srcHeight - 1);

            // 获取源图像中点的颜色
            unsigned long pixel = getPixel(src, srcX, srcY);
            // 将颜色设置到目标图像中
            XPutPixel(dst, dstX, dstY, pixel);
        }
    }
}
// 双线性插值缩放图像
void RemoteDesktopClient::scaleImageBilinear(const XImage *src, XImage *dst)
{
    int srcWidth = src->width;
    int srcHeight = src->height;
    int dstWidth = dst->width;
    int dstHeight = dst->height;
    float scaleX = (float)srcWidth / dstWidth;
    float scaleY = (float)srcHeight / dstHeight;

    for (int dstY = 0; dstY < dstHeight; ++dstY)
    {
        for (int dstX = 0; dstX < dstWidth; ++dstX)
        {
            // 计算源图像中相对于当前目标像素的四个最近像素的位置
            int srcX0 = (int)(dstX * scaleX) - 1;
            int srcY0 = (int)(dstY * scaleY) - 1;
            int srcX1 = srcX0 + 1;
            int srcY1 = srcY0 + 1;

            // 确保不超出源图像边界
            srcX0 = std::max(0, std::min(srcX0, srcWidth - 1));
            srcY0 = std::max(0, std::min(srcY0, srcHeight - 1));
            srcX1 = std::max(0, std::min(srcX1, srcWidth - 1));
            srcY1 = std::max(0, std::min(srcY1, srcHeight - 1));

            // 获取四个最近像素的值
            unsigned long pixel00 = getPixel(src, srcX0, srcY0);
            unsigned long pixel10 = getPixel(src, srcX1, srcY0);
            unsigned long pixel01 = getPixel(src, srcX0, srcY1);
            unsigned long pixel11 = getPixel(src, srcX1, srcY1);

            // 计算权重
            float fracX = (dstX * scaleX) - (int)(dstX * scaleX);
            float fracY = (dstY * scaleY) - (int)(dstY * scaleY);

            // 双线性插值计算新像素值
            unsigned long r = (1 - fracX) * (1 - fracY) * ((pixel00 >> 16) & 0xFF) +
                              fracX * (1 - fracY) * ((pixel10 >> 16) & 0xFF) +
                              (1 - fracX) * fracY * ((pixel01 >> 16) & 0xFF) +
                              fracX * fracY * ((pixel11 >> 16) & 0xFF);

            unsigned long g = (1 - fracX) * (1 - fracY) * ((pixel00 >> 8) & 0xFF) +
                              fracX * (1 - fracY) * ((pixel10 >> 8) & 0xFF) +
                              (1 - fracX) * fracY * ((pixel01 >> 8) & 0xFF) +
                              fracX * fracY * ((pixel11 >> 8) & 0xFF);

            unsigned long b = (1 - fracX) * (1 - fracY) * (pixel00 & 0xFF) +
                              fracX * (1 - fracY) * (pixel10 & 0xFF) +
                              (1 - fracX) * fracY * (pixel01 & 0xFF) +
                              fracX * fracY * (pixel11 & 0xFF);

            // 设置目标图像的像素值
            XPutPixel(dst, dstX, dstY, (r << 16) | (g << 8) | b);
        }
    }
}
void RemoteDesktopClient::receiveImage()
{
    if (!connectToDisplayServer())
    {
        std::cerr << "Failed to connect to display server" << std::endl;
        net_tools.closeSocket(display_client_fd);
        return;
    }

    ImageInfo ii;
    if (net_tools.receive(display_client_fd, (char *)&ii, sizeof(ii), 0) < 0)
    {
        std::cerr << "Incomplete image size received" << std::endl;
        return;
    }
    // 接收图像大小
    size_t image_size = ii.bits_per_pixel * ii.height * ii.width;
    // std::cout << "Image size: " << image_size << std::endl;
    std::vector<char> image_data(image_size);

    // 接收图像数据
    if (net_tools.receive(display_client_fd, image_data.data(), image_data.size(), 0) < 0)
    {
        std::cerr << "Incomplete image data received" << std::endl;
        net_tools.closeSocket(display_client_fd);

        return;
    }
    net_tools.closeSocket(display_client_fd);

    XImage *ximage = deserializeImage(image_data, ii.width, ii.height);
    if (!ximage)
    {
        std::cerr << "Failed to create ximage" << std::endl;
        return;
    }

    XImage *scaledImage = NULL;
    int dstWidth = 0;
    int dstHeight = 0;
    std::lock_guard<std::mutex> lock(mtxWindowMutex);
    {
        dstWidth = this->width;
        dstHeight = this->height;
    }
    // 调整窗口客户区大小
    XResizeWindow(display, window, dstWidth, dstHeight);
    // 等待X事件处理完成
    // XSync(display, False);
    // 请求更新窗口显示
    // XClearWindow(display, window);
    XMapWindow(display, window);
    XFlush(display);
    usleep(20000);

    scaledImage = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)), 24, ZPixmap, 0, nullptr, dstWidth, dstHeight, 32, 0);
    if (!scaledImage)
    {
        std::cerr << "Failed to create scaledImage" << std::endl;
        return;
    }

    scaledImage->data = (char *)malloc(scaledImage->bits_per_pixel / 8 * scaledImage->height * scaledImage->width);
    // std::cout << "scaledImage, width: " << scaledImage->width << " height: " << scaledImage->height << " bits_per_pixel: " << scaledImage->bits_per_pixel / 8 << std::endl;
    // 缩放图像
    scaleImageNearest(ximage, scaledImage);

    XMapWindow(display, window);

    // 显示图像
    GC gc = XDefaultGC(display, DefaultScreen(display));

    XPutImage(display, window, gc, scaledImage, 0, 0, 0, 0, scaledImage->width, scaledImage->height);
    XFlush(display);

    // 清理资源
    if (ximage)
        XDestroyImage(ximage);
    if (scaledImage)
        XDestroyImage(scaledImage);
}
void *RemoteDesktopClient::startDisplayImage(void *arg)
{
    RemoteDesktopClient *instance = static_cast<RemoteDesktopClient *>(arg);

    std::cout << "Display thread starting" << std::endl;

    // while (!instance->signal_wraper.isShutdownRequested())
    while (0 == shutdown_requested)
    {
        // 接收图像数据
        instance->receiveImage();
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
    }
    std::cout << "Display thread exiting" << std::endl;
    return NULL;
}
void RemoteDesktopClient::captureXevent()
{
    XSelectInput(display, window, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | StructureNotifyMask);

    XEvent event;

    // 等待事件
    XNextEvent(display, &event); // 阻塞型
    // if (XCheckIfEvent(display, &event, NULL, (XPointer)window)) // 非阻塞型
    {
        if (event.type == ConfigureNotify)
        {
            // 窗口大小改变事件
            int newWidth = event.xconfigure.width;
            int newHeight = event.xconfigure.height;
            if (newWidth != width || newHeight != height)
            {
                std::cout << "Window resized to width: " << newWidth << " height: " << newHeight << std::endl;
                std::lock_guard<std::mutex> lock(mtxWindowMutex);
                {
                    // 调整自定义窗口大小
                    this->width = newWidth;
                    this->height = newHeight;

                    // // 调整窗口客户区大小
                    // XResizeWindow(display, window, this->width, this->height);
                    // // 等待X事件处理完成
                    // XSync(display, False);
                    // // 请求更新窗口显示
                    // XClearWindow(display, window);
                }
            }
        }
        else
        {
            if (!connectToControllerServer())
            {
                std::cerr << "Failed to connect to controller server" << std::endl;
                return;
            }
            std::cout << "Connected to controller server, dispatch event: " << event.type << std::endl;
            if (net_tools.dispatch(controller_client_fd, (char *)&event, sizeof(event), 0) < 0)
            {
                std::cerr << "Failed to send event" << std::endl;

                net_tools.closeSocket(controller_client_fd);
                return;
            }
            net_tools.closeSocket(controller_client_fd);
        }
    }
    return;
}
void *RemoteDesktopClient::startCaptureXEvent(void *arg)
{
    RemoteDesktopClient *instance = static_cast<RemoteDesktopClient *>(arg);
    std::cout << "XEvent thread starting" << std::endl;
    // while (!instance->signal_wraper.isShutdownRequested())
    while (0 == shutdown_requested)
    {
        instance->captureXevent();
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    std::cout << "XEvent thread exiting" << std::endl;
    return NULL;
}
void RemoteDesktopClient::scaleWindow()
{
    // std::lock_guard<std::mutex> lock(mtxWindowMutex);
    {
        XSelectInput(display, window, ExposureMask | StructureNotifyMask);
    }
    // XMapWindow(display, window);
    // XFlush(display);

    XEvent event;
    // while (XPending(display))
    {
        XNextEvent(display, &event);
        if (event.type == ConfigureNotify)
        {
            // 窗口大小改变事件
            int newWidth = event.xconfigure.width;
            int newHeight = event.xconfigure.height;
            if (newWidth != width || newHeight != height)
            {
                std::cout << "Window resized to width: " << newWidth << " height: " << newHeight << std::endl;
                // std::lock_guard<std::mutex> lock(mtxWindowMutex);
                {
                    // 调整自定义窗口大小
                    this->width = newWidth;
                    this->height = newHeight;

                    // 调整窗口客户区大小
                    XResizeWindow(display, window, width, height);
                    // 等待X事件处理完成
                    XSync(display, False);
                    // 请求更新窗口显示
                    XClearWindow(display, window);
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}
void *RemoteDesktopClient::startscaleWindow(void *arg)
{
    RemoteDesktopClient *instance = static_cast<RemoteDesktopClient *>(arg);
    std::cout << "scaleWindow thread starting" << std::endl;
    // while (!instance->signal_wraper.isShutdownRequested())
    while (0 == shutdown_requested)
    {
        instance->scaleWindow();
        // std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    std::cout << "scaleWindow thread exiting" << std::endl;
    return NULL;
}
void RemoteDesktopClient::start()
{
    // 创建桌面显示线程
    if (pthread_create(&display_thread, NULL, &RemoteDesktopClient::startDisplayImage, this) != 0)
    {
        std::cerr << "display_thread create Failed" << std::endl;
        return;
    }

    // 创建处理鼠标键盘事件线程
    if (pthread_create(&event_thread, NULL, &RemoteDesktopClient::startCaptureXEvent, this) != 0)
    {
        std::cerr << "event_thread create Failed" << std::endl;
        return;
    }

    // 创建窗口缩放事件线程
    // if (pthread_create(&scale_thread, NULL, &RemoteDesktopClient::startscaleWindow, this) != 0)
    // {
    //     std::cerr << "scale_thread create Failed" << std::endl;
    //     return;
    // }
    pthread_join(display_thread, NULL);
    pthread_join(event_thread, NULL);
    // pthread_join(scale_thread, NULL);

    std::cout << "client thread exit." << std::endl;
}
// 反序列化字节流到XImage
XImage *RemoteDesktopClient::deserializeImage(const std::vector<char> &buffer, int src_width, int src_height)
{
    XImage *ximage = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)), 24, ZPixmap, 0, (char *)buffer.data(), src_width, src_height, 32, 0);
    if (!ximage)
    {
        std::cerr << "Failed to create XImage" << std::endl;
        return nullptr;
    }
    ximage->data = new char[buffer.size()];
    memcpy(ximage->data, buffer.data(), buffer.size());
    return ximage;
}

int main()
{
    signal(SIGINT, signal_handler); // 注册信号处理函数
    std::string strServerIP;
    uint16_t usDisplayPort, usControllerPort;
    std::shared_ptr<IniFileParser> iniParserPtr = std::make_shared<IniFileParser>("../config.ini");
    if (!iniParserPtr->getStrValue("ip", strServerIP))
    {
        return EXIT_FAILURE;
    }
    std::cout << "ip: " << strServerIP << std::endl;

    int port;
    if (!iniParserPtr->getIntValue("display port", port))
    {
        return EXIT_FAILURE;
    }
    if (port < 0 || port > std::numeric_limits<uint16_t>::max())
    {
        std::cerr << "Invalid port number " << port << std::endl;
        return EXIT_FAILURE;
    }
    else if (port > 0 && port < 1024) // 知名端口，通常被IANA（互联网号码分配机构）分配给一些公认的服务
    {
        std::cerr << "port number " << port << " is not available." << std::endl;
        return EXIT_FAILURE;
    }
    else
    {
        usDisplayPort = static_cast<uint16_t>(port);
    }
    std::cout << "display port: " << usDisplayPort << std::endl;
    if (!iniParserPtr->getIntValue("controller port", port))
    {
        return EXIT_FAILURE;
    }
    if (port < 0 || port > std::numeric_limits<uint16_t>::max())
    {
        std::cerr << "Invalid port number " << port << std::endl;
        return EXIT_FAILURE;
    }
    else if (port > 0 && port < 1024) // 知名端口，通常被IANA（互联网号码分配机构）分配给一些公认的服务
    {
        std::cerr << "port number " << port << " is not available." << std::endl;
        return EXIT_FAILURE;
    }
    else
    {
        usControllerPort = static_cast<uint16_t>(port);
    }
    std::cout << "controller port: " << usControllerPort << std::endl;

    int width, height;
    if (!iniParserPtr->getIntValue("width", width))
    {
        return EXIT_FAILURE;
    }
    if (width < 0)
    {
        std::cerr << "Invalid width " << width << std::endl;
        return EXIT_FAILURE;
    }
    std::cout << "width: " << width << std::endl;

    if (!iniParserPtr->getIntValue("height", height))
    {
        return EXIT_FAILURE;
    }
    if (height < 0)
    {
        std::cerr << "Invalid height " << height << std::endl;
        return EXIT_FAILURE;
    }
    std::cout << "height: " << height << std::endl;

    RemoteDesktopClient client(strServerIP, usDisplayPort, usControllerPort, width, height);

    client.start();

    return EXIT_SUCCESS;
}